#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2025-2026 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#使用方法
# python apiCheck.py --sdk=xxxx
##  python apiCheck.py --sdk=xxxx --includePaths="xx,xx"
## python apiCheck.py --sdk=/srv/code/out/sdk/ohos-sdk/linux，其中linux包含ets/ets1.2目录

import platform
import subprocess
import os
import tempfile
import json
import argparse
from collections import defaultdict
import shutil
import sys

parser = argparse.ArgumentParser(description='manual to this script')
parser.add_argument("--sdk", type=str, default="")
parser.add_argument("--scan", type=str, default="")
parser.add_argument("--es2pandaPath", type=str)
parser.add_argument("--includePaths", type=str)
args = parser.parse_args()


global_ohSdk = '' # sdk路径
global_scanPath= '' # 扫描路径
sep = os.sep # 系统分隔符

if args.sdk != "" and args.scan != "":
        global_ohSdk = args.sdk
        global_scanPath = args.scan
elif args.sdk != "" and args.scan == "":
        global_ohSdk = args.sdk
        global_scanPath = args.sdk+'/ets/ets1.2/api'


global_es2pandaPath = args.es2pandaPath if args.es2pandaPath else global_ohSdk + '/ets/ets1.2/build-tools/ets2panda' # es2panda路径 
global_includePaths = [item.strip() for item in args.includePaths.split(',')] if args.includePaths else []

# 扫描此四个文件夹下的文件
def scanFun(paths_dict):
    scan_path_list = [f'{sep}api{sep}',f'{sep}arkts{sep}',f'{sep}component{sep}',f'{sep}kits{sep}']
    
    for root, dirs, files in os.walk(f"{global_ohSdk}{sep}ets{sep}ets1.2", followlinks=True):
        absPath = os.path.abspath(root)
        for file in files:
            # 只扫描.ets文件
            if 'd.ets' in file:
                # 拼凑获取绝对路径
                file_path = os.path.join(absPath, file)
                for scan_path in scan_path_list:
                    if scan_path in file_path:
                        key = ''
                        val = file_path.split('.d.')[0]
                        # if f'{sep}arkui{sep}' not in file_path:
                        #     # 碰到多级目录，则文件名前面加上目录名，用'.'来分割
                        #     path_list = val.split(scan_path)[1].split(sep)
                        #     key = '.'.join(path_list)
                        # else:
                        #     # arkui/的为组件，不用分割
                        #     key = file.split('.d.')[0]
                        path_list = val.split(scan_path)[1].split(sep)
                        # print(path_list)
                        if not path_list[-1].startswith('@'):
                            path_list = val.split(scan_path)[1].split(sep)
                            key = '.'.join(path_list)
                        else:
                            key = file.split('.d.')[0]
                        # print(key)
                        paths_dict[key] = [val]
                        # 如果匹配到scan_path_list中任意一个路径，那么直接break，提升性能
                        break

    return paths_dict

# 使用目录下面的情况
def createArktsconfig():
    configJsonF = open(f'{global_es2pandaPath}/bin/arktsconfig.json', 'r+')
    configDict = json.load(configJsonF)
    configJsonF.close()
    configDict["compilerOptions"]["package"] = "entry"
    currentDict = configDict["compilerOptions"]
    currentDict  = configDict["compilerOptions"]["paths"]
    
    # 修改相对路径为绝对路径
    for key in currentDict:
        if '../' in currentDict[key][0]:
            currentDict[key][0] = f"{global_es2pandaPath}/bin/{currentDict[key][0]}"

    # 扫描方法
    paths_dict = scanFun({})
    # 将扫描后的dict拼起来
    currentDict.update(paths_dict)
    # 创建一个临时文件，并将内存中的数据写到临时文件
    with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.json') as temp_file:
        data = configDict
        # 读取临时文件
        json.dump(data, temp_file)
        temp_file_path = temp_file.name
    return temp_file_path

# 扫描路径下面的ets
def checksdk():
    all = 0
    timeout = 0
    compile_error = 0
    compile_warning = 0
    compile_pass = 0
    compile_dump = 0
    pass_list = []
    # 指定临时编译abc文件的路径
    abc_folder_path = './tempabc'
    if os.path.exists(abc_folder_path):
        if os.path.isdir:
            # 使用shutil.rmtree()函数删除文件夹及其所有内容
            shutil.rmtree(abc_folder_path)
        else:
            os.remove(abc_folder_path)
    # 使用os.makedirs()方法创建文件夹，如果文件夹已存在会抛出异常
    os.mkdir(abc_folder_path)

    temp_arktsconfig_path = createArktsconfig()
    
    # 首先计算需要处理的文件总数
    total_files = 0
    for root, dirs, files in os.walk(global_scanPath, followlinks=True):
        for file in files:
            file_path = os.path.join(root, file)
            if '.d.ets' not in file_path and '.d.ts' not in file_path:
                continue
            if len(global_includePaths) > 0 and file not in global_includePaths:
                continue
            total_files += 1
    
    # in api folder
    for root, dirs, files in os.walk(global_scanPath, followlinks=True):
        with open('../out/sdk/api_checker.log', 'a', encoding='utf-8') as log_print:
            for file in files:
                file_path = os.path.join(root, file)
                if '.d.ets' not in file_path and '.d.ts' not in file_path:
                    continue
                if len(global_includePaths) > 0 and file not in global_includePaths:
                    continue
                all += 1
                try:
                    if platform.system() == 'Windows':
                        excutefile = global_es2pandaPath + '/bin/es2panda.exe'
                    else:
                        excutefile = global_es2pandaPath + '/bin/es2panda'
                    command = [excutefile, '--extension', 'ets','--arktsconfig', temp_arktsconfig_path, '--ets-module', file_path, "--output", abc_folder_path+'/'+file+'.abc']
                    print('')
                    print(' '.join(command))
                    log_print.write(' '.join(command) + '\n')
                    result = subprocess.run(command, capture_output=True, text=True, timeout=10)
                    if len(result.stdout) == 0:
                        compile_pass += 1
                        pass_list.append(file_path)
                    else:
                        
                        lst = result.stdout.split('\n')
                        for info in lst:
                            if (len(info) == 0):
                                continue
                            if 'Warning' in info:
                                compile_warning += 1
                                continue
                            print(f"{file_path} ----- {file} ----- {info}")
                            log_print.write(f"{file_path} ----- {file} ----- {info}" + '\n')
                            compile_error += 1
                    if len(result.stderr) != 0:
                        compile_dump += 1
                except subprocess.TimeoutExpired as e:
                    timeout += 1

    print("all:", all, "\ntimeout:", timeout, "\ncompile_error:", compile_error, "\ncompile_warning:", compile_warning,
          "\ncompiler_dump:", compile_dump, "\ncompile_pass:", compile_pass)
    # 删除临时文件
    os.remove(temp_arktsconfig_path)
    # 使用shutil.rmtree()函数删除文件夹及其所有内容
    shutil.rmtree(abc_folder_path)
    # 如果编译错误大于0，则退出程序
    if compile_error > 0:
        sys.exit(1)

if __name__ == "__main__":
    checksdk()
